package com.emmmya.ocs.config.interceptor;

import com.emmmya.ocs.config.redis.ShiroRedisManager;
import com.emmmya.ocs.modules.system.entity.User;
import com.emmmya.ocs.modules.system.utils.UserUtils;
import com.emmmya.ocs.common.constant.RedisConstant;
import com.emmmya.ocs.common.utils.FileNameUtil;
import com.emmmya.ocs.common.utils.HResourcesUtil;
import com.emmmya.ocs.config.SystemConfig;
import com.emmmya.ocs.config.redis.RedisManager;
import com.emmmya.ocs.config.security.jwt.JwtConfig;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.thymeleaf.util.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 因为一开始没有redis。所以这个过期时间配置在toekn里面。
 */
@Slf4j
public class JwtTokenInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    RedisManager redisManager;

    @Autowired
    ShiroRedisManager shiroRedisManager;

    @Autowired
    JwtConfig jwtConfigs;

    @Autowired
    UserUtils userUtils;

    @Autowired
    SystemConfig systemConfig;

    @Autowired
    private ShiroFilterFactoryBean shiroFilterFactoryBean;


    private List<String> allowGet = getAllowGet();

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws SignatureException, IOException, ServletException {
        String uri = request.getRequestURI();

        //优先判断的集合
        Map<String, String> map = shiroFilterFactoryBean.getFilterChainDefinitionMap();
        SavedRequest savedRequest = WebUtils.getSavedRequest(request);


        /** 地址过滤 */
        //先判断shiro的集合中是否放行，是的话，直接过。
        if(map.containsKey(uri)){
            String s = map.get(uri);
            if("anon".equals(s)){
                return true;
            }
        }
//        boolean activeState = SystemConfig.activeState;
//        if(!activeState){
//            return true;
//        }

        if ("/login".equals(uri)){
            return true ;
        }

        if(userUtils.getCurrentUser() == null){
            request.setAttribute("targetURI",uri);
            request.getRequestDispatcher("/login").forward(request,response);
            return false;
        }
        String token = "";
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User) subject.getPrincipal();

        //if(!StringUtils.isEmpty(redisKeyUser)) {
        if(currentUser != null){
            token = (String) redisManager.get(RedisConstant.REDIS_USER_TOKEN+currentUser.getUsername());
        }


        //如果token为空。或者为null字符串，或者token已失效
        if(StringUtils.isEmpty(token) || "null".equals(token)) {
            /** Token 验证 */
            //如果是循序get请求行携带token的url，则从request中获取
            if (allowGet == null) {
                //throw new FileNotFoundException("未找到允许get请求在请求行中携带token的接口名");
            }
            //如果是允许get请求方式在请求行携带token的话，获取request参数中的token
            else if (allowGet.contains(uri)) {
                token = request.getParameter(jwtConfigs.getHeader());
            }
            //如果上面if没有获取到，其他情况只能在请求头获取
            else  {
                token = request.getHeader(jwtConfigs.getHeader());
            }
        }
        if(StringUtils.isEmpty(token) || "null".equals(token)){
            // throw new SignatureException(jwtConfigs.getHeader()+ "不能为空");
            if(savedRequest != null) {
                request.setAttribute("targetURI", savedRequest.getRequestUrl());
            }
            request.getRequestDispatcher("/login").forward(request,response);
            return false;
        }
        Claims claims = null;
        try{
            claims = jwtConfigs.getTokenClaim(token);
            if(claims == null || jwtConfigs.isTokenExpired(claims.getExpiration())){
                //subject.logout();
                request.setAttribute("message"," token失效，请重新登录。");
                request.setAttribute("tokenCode","false");
                if(savedRequest != null) {
                    request.setAttribute("targetURI", savedRequest.getRequestUrl());
                }
                request.getRequestDispatcher("/login").forward(request,response);
                return false;
                //throw new SignatureException(jwtConfigs.getHeader() + "失效，请重新登录。");
            }
            //查询redis校验token
            String rToken = (String) redisManager.get(RedisConstant.REDIS_USER_TOKEN + jwtConfigs.getUsernameFromToken(token));
            if(!token.equals(rToken)){
                //subject.logout();
                redisManager.del(RedisConstant.REDIS_USER_TOKEN+jwtConfigs.getUsernameFromToken(token));
                request.setAttribute("message","token与redis数据不符合，请重新登录。");
                request.setAttribute("tokenCode","false");
                request.setAttribute("token",token);
                request.setAttribute("rToken",rToken);
                if(savedRequest != null) {
                    request.setAttribute("targetURI", savedRequest.getRequestUrl());
                }
                request.getRequestDispatcher("/login").forward(request,response);
                return false;
                //throw new SignatureException(jwtConfigs.getHeader() + "失效，请重新登录。");
            }
        }catch (Exception e){
            //subject.logout();
            request.setAttribute("message","校验token，抛出异常，请重新登录。如有问题请联系管理员！");
            request.setAttribute("tokenCode","false");
            if(savedRequest != null) {
                request.setAttribute("targetURI", savedRequest.getRequestUrl());
            }
            request.getRequestDispatcher("/login").forward(request,response);
            log.error(""+e.getLocalizedMessage()+"\\n"+e.getMessage());
            return false;
            //throw new SignatureException(jwtConfigs.getHeader() + "失效，请重新登录。");
        }

        /** 设置 identityId 用户身份ID */
        request.setAttribute("identityId", claims.getSubject());
        return true;
    }

    //
    private List<String> getAllowGet(){
        try {
            File templates = HResourcesUtil.getResources("\\templates");
            if(templates.isDirectory()){
                String[] list = templates.list();
                List<String> allowGet = FileNameUtil.subLastSign(Arrays.asList(list), ".html");
                allowGet = FileNameUtil.addPrefix(allowGet, "/");
                return allowGet;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ArrayList<>();
    }
}
